import { DragSource } from 'react-dnd';
import { getElement } from '@design/core/utils/dom';

function getDragSpec(options = {}) {
  return {
    beginDrag(props) {
      let { node } = props;
      let isNew = false;
      if (typeof node === 'function') {
        node = node();
        isNew = true;
      }
      if (!isNew) {
        const element = getElement(node.key);
        return { node, isNew, element };
      }
      return { node, isNew };
    },
    endDrag(props, monitor) {
      if (!monitor.didDrop()) {
        return;
      }
      const { node, isNew } = monitor.getItem();
      const { target, editor, index } = monitor.getDropResult();
      if (isNew) {
        editor.insertNodeByKey(node, target.key, index);
        return;
      }
      editor.moveNode(node.key, target.key, index);
    }
  };
}

function DragDecorator(options = {}) {
  const { type = 'block', dropEffect = 'move', offset = {} } = options;
  function collect(connect, monitor) {
    const connectDragSource = (node, options) => {
      return connect.dragSource()(node, { dropEffect, ...options });
    };
    const connectDragPreview = (node, options) => {
      return connect.dragPreview()(node, { ...offset, ...options });
    };
    return {
      connectDragPreview,
      connectDragSource,
      isDragging: monitor.isDragging()
    };
  }
  return Comp => {
    return DragSource(type, getDragSpec(), collect)(Comp);
  };
}

export default DragDecorator;
